//
// Created by 董一龙 on 2022/10/13.
//

#include "fqueue/segment_queue/mmap_queue/operator/ring_buffer_operator.h"
#include <algorithm>

namespace fqueue {
    bool ring_buffer_operator::meta_info_t::is_valid(const ring_buffer_operator::meta_info_t *meta) {
        return meta->magic_num == MAGIC_NUM;
    }
    ring_buffer_operator::meta_info_t *ring_buffer_operator::meta_info(void *buffer, size_t buffer_size) {
        return static_cast<meta_info_t *>(buffer);
    }

    uint8_t * ring_buffer_operator::data_buffer(void *buffer, size_t buffer_size, meta_info_t const* meta) {
        return static_cast<uint8_t *>(buffer) + sizeof(meta_info_t);
    }

    bool ring_buffer_operator::has_format(void *buffer, size_t buffer_size) {
        meta_info_t * meta = meta_info(buffer, buffer_size);
        return meta_info_t::is_valid(meta);
    }

    int ring_buffer_operator::format(void *buffer, size_t buffer_size) {

        meta_info_t * meta = meta_info(buffer, buffer_size);
        meta->magic_num = meta_info_t::MAGIC_NUM;
        meta->front = 0;
        meta->rear = 0;
        meta->capacity = buffer_size - sizeof(meta_info_t);
        if (buffer_size > sizeof(meta_info_t) || meta->capacity == 16777184) {
            assert(buffer_size > sizeof(meta_info_t));
        }

        meta->size = 0;
        meta->push_count = 0;
        meta->pop_count = 0;
        return 0;
    }

    size_t ring_buffer_operator::capacity(void *buffer, size_t buffer_size) {
        return meta_info(buffer, buffer_size)->capacity;
    }

    size_t ring_buffer_operator::size(void *buffer, size_t buffer_size) {
        return meta_info(buffer, buffer_size)->size;
    }

    int ring_buffer_operator::enqueue(void *buffer, size_t buffer_size, void const*input, size_t input_length) {
        if (input_length == 0) {
            return 0;
        }
        meta_info_t * meta = meta_info(buffer, buffer_size);
        uint8_t *data= data_buffer(buffer, buffer_size, meta);
        size_t size = meta->size;
        size_t capacity = meta->capacity;
        size_t byte_to_write = std::min(capacity - size, input_length);

        if (byte_to_write < meta->capacity - meta->rear) {
            memmove(data + meta->rear, input, input_length);
            meta->rear = (meta->rear + byte_to_write) % meta->capacity;
        }
        else {
            size_t size_1 = capacity - meta->rear;
            memmove(data + meta->rear, input, size_1);
            size_t size_2 = byte_to_write - size_1;
            memmove(data, input, size_2);
            meta->rear = size_2;
        }
        meta->size += byte_to_write;
        meta->push_count++;
        return byte_to_write;
    }

    int ring_buffer_operator::dequeue(void *buffer, size_t buffer_size, void *output, size_t output_length) {
        if (output_length == 0) {
            return 0;
        }
        meta_info_t * meta = meta_info(buffer, buffer_size);
        uint8_t *data= data_buffer(buffer, buffer_size, meta);
        size_t size = meta->size;
        size_t capacity = meta->capacity;
        size_t byte_to_read = std::min(size, output_length);
        // 0001111000
        if (byte_to_read <= meta->capacity - meta->front) {
            memmove(output, data + meta->front, byte_to_read);
            meta->front = (meta->front + byte_to_read) % meta->capacity;
        }
        else {
            size_t size_1 = capacity - meta->front;
            memmove(output, data + meta->front, size_1);
            size_t size_2 = byte_to_read - size_1;
            memmove((uint8_t *)output + size_1, data, size_2);
            meta->front = size_2;
        }
        meta->size -= byte_to_read;
        meta->pop_count++;
        return byte_to_read;
    }

    int ring_buffer_operator::clear(void *buffer, size_t buffer_size) {
        memset(buffer, 0, buffer_size);
        return 0;
    }

} // fqueue